home *** CD-ROM | disk | FTP | other *** search
- package sub_arctic.lib;
-
- import sub_arctic.input.event;
- import sub_arctic.input.callback_object;
- import sub_arctic.input.inout_draggable;
- import sub_arctic.input.pressable;
-
- import sub_arctic.output.color_pair;
- import sub_arctic.output.loaded_image;
- import sub_arctic.output.drawable;
-
- import sub_arctic.lib.sub_arctic_error;
-
- import java.awt.Point;
- import java.awt.Dimension;
- import java.awt.Image;
- import java.awt.Font;
- import java.awt.FontMetrics;
- import java.awt.Color;
-
- /**
- * This class implements a multi-state button object. It can have any
- * number of states and may have transitions between those states with
- * individual looks.
- *
- * @author Scott Hudson
- */
- public class multi_button extends base_interactor
- implements inout_draggable, pressable {
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Full constructor. The two image sets provided give normal appearance
- * for each state of the button, and a transition appearance out of each
- * state of the button. The transition set may be coded as null in which
- * case the next state image is used when a transition is needed. Otherwise
- * the two image sets must be the same size.
- *
- * @param int x x position of this object
- * @param int y y position of this object
- * @param loaded_image[] st_looks the set of images for the looks of this
- * object
- * @param loaded_image[] trans_looks the set of images for the looks of
- * transitions of this object.
- * @param callback_object call_obj the object to send the callbacks to.
- */
- public multi_button(
- int x,
- int y,
- loaded_image[] st_looks,
- loaded_image[] trans_looks,
- callback_object call_obj)
- {
- super(x,y);
-
- /* if the st_looks is null, we allow that because subclasses
- * may not yet have had time to compute the images for the
- * buttons
- */
-
- /* check for transitions not being the right size */
- if (trans_looks != null && trans_looks.length != st_looks.length)
- throw new sub_arctic_error("Normal and transition image sets of "+
- "unequal size passed to multi_button()");
-
- /* save the instance vars */
- set_looks(st_looks, trans_looks);
- _callback_obj = call_obj;
-
- /* initially in state 0 and not in transition */
- _cur_state = 0;
- _in_transition = false;
-
- /* calculate correct initial size */
- calc_size();
- }
-
- //had:
- //* @exception bad_value thrown if the set of images passed in are not of a
- //* legitimate size or the number of transitions is
- //* different from the number of states
- //* @exception general PROPAGATED
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * This interactor determines width and height internally, and does not
- * intrinsically constrain part_a.
- * @return int the constant mask for an internal width and height
- */
- public int intrinsic_constraints()
- {
- /* take part_a out and put w & h in */
- return (super.intrinsic_constraints() & ~PART_A) | W | H;
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Internal indicator of whether we are currently in transition from
- * one state to the next.
- */
- protected boolean _in_transition = false;
-
- /**
- * Index of current state.
- */
- protected int _cur_state = 0;
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Return the value of the part_a component of this object. In our case
- * this is stored in _cur_state.
- */
- public int part_a()
- {
- /* Make sure its up to date then return it */
- eval_part_a();
- return _cur_state;
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Set part_a value directly bypassing the constraint system (but doing
- * damage). In this case part_a is stored in _cur_state.
- *
- * @param int v the new value for part_a.
- */
- protected void set_raw_part_a(int v)
- {
- /* force v in range */
- if (v < 0) v = 0;
- if (v >= state_looks().length) v = state_looks().length-1;
-
- /* don't do anything unless this is a change */
- if (v != _cur_state)
- {
- /* make change and do damage */
- _cur_state = v;
- damage_self();
- }
- }
-
- //had:
- //* @exception general
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Set the part_a component of this object. In our case this is stored in
- * _cur_state.
- *
- * @param int v the new value of part_a.
- */
- public void set_part_a(int v)
- {
- /* if this has a constraint throw an exception */
- if ((active_constraints() & PART_A) != 0)
- throw new sub_arctic_error(
- "Attempt to assign value to constrained part_a (AKA cur_state)");
-
- /* don't do anything unless this is a change */
- if (v != _cur_state)
- {
- set_raw_part_a(v);
- mark_part_a_ood();
- }
- }
-
- //had:
- //* @exception cannot_assign if part_a has a constraint attached to it.
- //* @exception general
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Index of current state. For toggles, "off" or "unchecked" is zero.
- * The object starts in state 0 by default. This is mirrored as part_a
- * for this object.
- *
- * @return int the current state from 0 to n-1
- */
- public int cur_state()
- {
- return part_a();
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Set index of current state. For toggles, "off" or "unchecked" is zero.
- * This is mirrored as part_a for this object.
- *
- * @param int the new current state.
- */
- public void set_cur_state(int st)
- {
- set_part_a(st);
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Indicate what the next state will be. Be default we just increment
- * wrapping back to zero as needed.
- *
- * @return int the next state.
- */
- public int next_state()
- {
- return (cur_state() + 1) % state_looks().length;
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /** Image set for "normal" appearance in each state. */
- protected loaded_image[] _state_looks;
-
- /**
- * Image set for "normal" appearance in each state.
- *@return the array of images for the normal states
- */
- public loaded_image[] state_looks() {return _state_looks;}
-
- /**
- * Get the "normal" appearance image for a given state.
- * @parm int the state to retrieve the image for
- * @return loaded_image the image for the asked for state
- */
- public loaded_image get_state_look(int indx) {return _state_looks[indx]; }
-
- /**
- * Set the "normal" appearance image for a given state.
- * @param int index the state being modified
- * @param int loaded_image img the new image to use for this state
- */
- public void set_state_look(int indx, loaded_image img)
- {
- /* set the image */
- _state_looks[indx] = img;
-
- /* force size recalc */
- calc_size();
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Image set for "transition" appearance from each state.
- */
- protected loaded_image[] _transition_looks;
-
- /**
- * Image set for "transition" appearance from each state.
- * @return loaded_image the set of images for the transitions
- */
- public loaded_image[] transition_looks() {return _transition_looks;}
-
- /**
- * Get the "transition" appearance image from a given state.
- * @param int indx the state transition of interest
- * @return loaded_image the image for the given state
- */
- public loaded_image get_transition_look(int indx)
- {
- return _transition_looks[indx];
- }
-
- /**
- * Set the "transition" appearance image from a given state.
- * @param int indx the index of the transition to be modified
- * @param loaded_image img the new image to use for that transition
- */
- public void set_transition_look(int indx, loaded_image img)
- {
- /* set the image */
- _transition_looks[indx] = img;
-
- /* force size recalc */
- calc_size();
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Set both "normal" and "transition" image sets. The normal image for
- * each state is displayed when the button is quiescent in that state.
- * The transition image is shown when the mouse button has been depressed
- * over the button and releasing it would cause a transition to the next
- * state. The transition set may be coded as null in which
- * case the next state image is used when a transition is needed. Otherwise
- * the two image sets must be the same size.
- *
- * @param loaded_image[] st_looks the looks for the states.
- * @param loaded_image[] trans_looks the looks for the transitions.
- */
- public void set_looks(loaded_image[] st_looks, loaded_image[] trans_looks)
- {
-
- /* we allow the set of looks to be null so that they can be
- used as placeholds for a later change */
-
- /* check for the set of transitions being the right size */
- if (trans_looks != null && trans_looks.length != st_looks.length)
- throw new sub_arctic_error("Normal and transition image sets "+
- "of unequal size passed to set_looks()");
-
- /* save the instance vars */
- _state_looks = st_looks;
- _transition_looks = trans_looks;
-
- /* recalculate new sizes */
- calc_size();
- }
-
- //had:
- //* @exception bad_value thrown if the set of images passed in are not of a
- //* legitimate size or the number of transitions is
- //* different from the number of states.
- //* @exception general PROPAGATED
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /** Object we make callbacks to */
- protected callback_object _callback_obj;
-
- /**
- * Object that this button makes callbacks to when pressed. All callbacks
- * have a callback number of 0 and the callback_info field contains an
- * Integer object indicating the new state of the button.
- *
- * @return callback_object the object to send the callbacks to
- */
- public callback_object callback_obj() {return _callback_obj;}
-
- /**
- * Set the callback object that this button makes callbacks to when pressed.
- * All callbacks have a callback number of 0 and the callback_info field
- * contains an Integer object indicating the new state of the button.
- *
- * @param callback_object the new receiver of callbacks
- */
- public void set_callback_obj(callback_object cb) {_callback_obj = cb;}
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /** (Re)calculate size as max of images. */
- protected void calc_size()
- {
- int max_w = 0;
- int max_h = 0;
-
- /* if you don't have any images, we make you 10x10 */
- if (_state_looks==null) {
- max_w=10;
- max_h=10;
- set_intrinsic_size(max_w, max_h);
- return;
- }
-
- /* calculate max of state appearance images */
- for (int i = 0; i < _state_looks.length; i++)
- if (state_looks()[i] != null)
- {
- if (state_looks()[i].width()> max_w)
- max_w = state_looks()[i].width();
- if (state_looks()[i].height() > max_h)
- max_h = state_looks()[i].height();
- }
-
- /* if we have transition images, consider those also */
- if (transition_looks() != null)
- for (int i = 0; i < _state_looks.length; i++)
- if (transition_looks()[i] != null)
- {
- if (transition_looks()[i].width()> max_w)
- max_w = transition_looks()[i].width();
- if (transition_looks()[i].height() > max_h)
- max_h = transition_looks()[i].height();
- }
-
- /* if the size changes, reset it */
- if (max_w != w() || max_h != h())
- set_intrinsic_size(max_w, max_h);
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Handle mouse presses in our bounds. This makes us the inout drag
- * focus (most of the work is handled via the inout_drag protocol.
- *
- * @param event evt the event to be dispatched.
- * @param Object user_info the object passed to the pick_collector at pick
- * time.
- * @return boolean true if this event has been handled.
- */
- public boolean press(event evt, Object user_info)
- {
- /* make us the inout drag focus */
- manager.inout_drag_focus.set_focus_to(this, evt, user_info);
- return true;
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Companion for press() -- ignore here.
- * @param event evt the event to be dispatched.
- * @param Object user_info the object passed to the pick_collector at pick
- * time.
- * @return boolean true if this event has been handled.
- */
- public boolean release(event evt, Object user_info)
- {
- return false;
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Handle input corresponding to the start of an inout tracking drag.
- *
- * @param event evt the event to be dispatched
- * @param boolean starts_inside true if the drag starts inside the object
- * @param Object user_info the object passed to the inout_drag agent
- * when this object came into the focus set.
- * @return boolean true if this event has been handled
- */
- public boolean inout_drag_start(
- event evt,
- boolean starts_inside,
- Object user_info)
- {
- /* if we start inside then we are now in transition */
- _in_transition = starts_inside;
- damage_self();
-
- return true;
- }
-
- //had:
- //* @exception general PROPAGATED
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Handle "drag" into the bounds of the object.
- * @param event evt the event to be dispatched
- * @param Object user_info the object passed to the inout_drag agent when
- * this object came into the focus set.
- * @return boolean true if this event has been handled
- */
- public boolean inout_drag_enter(event evt, Object user_info)
- {
- /* change appearance and arrange for redraw */
- _in_transition = true;
- damage_self();
-
- return true;
- }
-
- //had:
- //* @exception general PROPAGATED
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Handle "drag" out of the bounds of the object.
- *
- * @param event evt the event to be dispatched.
- * @param Object user_info the object passed to the inout_drag agent when
- * this object came into the focus set.
- * @return boolean true if this event has been handled
- */
- public boolean inout_drag_exit(event evt, Object user_info)
- {
- /* change appearance and arrange for redraw */
- _in_transition = false;
- damage_self();
-
- return true;
- }
-
- //had:
- //* @exception general PROPAGATED
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /** Callback number constant for the button state transition callback. */
- public static final int BUTTON_ACTION_CALLBACK = 0;
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Invoke the callback object. This is basically here as a hook for
- * subclasses to override if they would prefer to do something other
- * than a normal callback.
- * @param event evt the event causing the callback
- */
- protected void do_callback(event evt)
- {
- if (callback_obj() != null)
- callback_obj().callback(this, evt, BUTTON_ACTION_CALLBACK,
- new Integer(cur_state()));
- }
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Handle input corresponding to the end of an inout drag. Invokes the
- * callback if we ended up inside the object.
- * @param event evt the event to be dispatched.
- * @param boolean ended_inside true if the drag ended inside the object.
- * @param Object user_info the object passed to the inout_drag agent
- * when this object came into the focus set.
- * @return boolean true if this event has been handled
- */
- public boolean inout_drag_end(
- event evt,
- boolean ended_inside,
- Object user_info)
- {
- /* if we ended up inside go to new state, do the callback, then redraw */
- if (ended_inside)
- {
- _in_transition = false;
- set_cur_state(next_state());
- do_callback(evt);
- damage_self();
- }
-
- return true;
- }
-
- //had:
- //* @exception general PROPAGATED
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
-
- /**
- * Draw the button
- * @param drawable d the surface to draw the object on
- */
- protected void draw_self_local(drawable d)
- {
- /* if you don't have any state looks, something is probably wrong */
- if (_state_looks==null) {
- return;
- }
-
- /* if we are in transition then draw the transition look */
- if (_in_transition)
- {
- /* if we have transition look from this state use it */
- if (transition_looks()!=null && transition_looks()[cur_state()]!=null)
- d.drawImage(transition_looks()[cur_state()],0,0);
- else
- /* otherwise use normal look of the next state */
- d.drawImage(state_looks()[next_state()], 0,0);
- }
- else
- {
- /* use normal appearance for current state */
- d.drawImage(state_looks()[cur_state()],0,0);
- }
- }
-
- //had:
- //* @exception general PROPAGATED
-
- /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */
- }
- /*=========================== COPYRIGHT NOTICE ===========================
-
- This file is part of the subArctic user interface toolkit.
-
- Copyright (c) 1996 Scott Hudson and Ian Smith
- All rights reserved.
-
- The subArctic system is freely available for most uses under the terms
- and conditions described in
- http://www.cc.gatech.edu/gvu/ui/sub_arctic/sub_arctic/doc/usage.html
- and appearing in full in the lib/interactor.java source file.
-
- The current release and additional information about this software can be
- found starting at: http://www.cc.gatech.edu/gvu/ui/sub_arctic/
-
- ========================================================================*/
-